import { CanvasTexture, ClampToEdgeWrapping, Mesh, NearestFilter, ShaderMaterial, UVMapping } from 'three'
import { CqkjMap } from '../Basic/CqkjMap'
import { DataElement } from '../Basic/DataElement'
import { getValue } from '../Util/common'
import { UNITSQUARE } from '../Util/static'

export interface LegendDataOption {
  /** 数据范围，[画布左边界对应的值，1：画布右边界对应的值] */
  range: [number, number]
  /** 一个512*1的画布 */
  canvas: HTMLCanvasElement
}

export class LegendData extends DataElement<LegendDataOption> {
  /** 数据贴图 */
  get texture () {
    return getValue(this._cache, 'texture', () => {
      const option = this.option
      return new CanvasTexture(option.canvas, UVMapping, ClampToEdgeWrapping, ClampToEdgeWrapping, NearestFilter, NearestFilter)
    })
  }

  debug (map: CqkjMap): void {
    const mesh = new Mesh(UNITSQUARE, new ShaderMaterial({
      transparent: true,
      depthWrite: false,
      depthTest: false,
      uniforms: {
        u_legend: {
          value: this.texture
        }
      },
      vertexShader: `
      varying vec2 v_uv;
     
      void main(){
          v_uv=uv;
          gl_Position=vec4(position.xy,-1.0,1.0);
      }
      `,
      fragmentShader: `
      varying vec2 v_uv;
      uniform sampler2D u_legend;
      void main(){
        gl_FragColor=texture2D(u_legend,v_uv);
      }
      `
    }))

    map.scene.add(mesh)
  }

  /**
   * 通过阈值列表创建图例
   * @param thresholds  阈值列表[值，颜色][];必须按顺序排列(包含正序反序)
   * @param step  如果设置代表为非渐变图例；每一个像素代表的值，推荐使用阈值间隔，如果阈值不均匀使用间隔的最大公约数
   * @param mcolor 非渐变图例中小于最小阈值的颜色
   * @returns 图例
   */
  static fromThresholds (thresholds: Array<[number, string]>, step?: number, mcolor?: string) {
    const canvas = document.createElement('canvas')
    canvas.width = 512
    canvas.height = 1
    const ctx = canvas.getContext('2d')!
    if (step) {
      if (mcolor) {
        ctx.fillStyle = mcolor
        ctx.fillRect(0, 0, 1, 1)
      }
      const min = thresholds[0][0]
      let offset = 1
      let color = thresholds[0][1]
      for (let i = 1; i < thresholds.length; i++) {
        const element = thresholds[i]
        const w = (element[0] - min) / step + 1 - offset
        ctx.fillStyle = color
        ctx.fillRect(offset, 0, w, 1)
        offset += w
        color = element[1]
      }
      if (offset > 511) {
        throw new Error('图例参数不合理')
      }
      ctx.fillStyle = color
      ctx.fillRect(offset, 0, 512 - offset, 1)
      return new LegendData({
        range: [min - step, min + step * 511],
        canvas
      })
    } else {
      const step = (thresholds[thresholds.length - 1][0] - thresholds[0][0]) / 510
      const min = thresholds[0][0] - step
      const length = step * 512
      const max = min + length

      const canvas = document.createElement('canvas')
      canvas.width = 512
      canvas.height = 1
      const ctx = canvas.getContext('2d')!

      const grd = ctx.createLinearGradient(0, 0, 512, 0)
      thresholds.forEach(e => {
        grd.addColorStop((e[0] - min) / length, e[1])
      })
      ctx.fillStyle = grd
      ctx.fillRect(0, 0, 512, 1)
      return new LegendData({
        range: [min, max],
        canvas
      })
    }
  }
}
